package com.hospital.common.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 统计相关计算公式
 * @author yhn
 * @version 1.0
 */
public class CalculateUtils {
    /**
     * 计算帖子热度分
     * @param likeCount 点赞数
     * @param replyCount 回复数
     * @param favoriteCount 收藏数
     */
    public static Long calculateHeatScore(Integer likeCount, Integer replyCount, Integer favoriteCount) {
        return (likeCount * 2L + replyCount * 3L + favoriteCount * 5L);
    }

    /**
     * 计算板块帖子精华率
     * @param pinnedPostCount 精华帖总数
     * @param totalPostCount 总帖数
     */
    public static Double calculateSectionPinnedPostRatio(Long pinnedPostCount, Long totalPostCount) {
        return calculatePercentage(pinnedPostCount, totalPostCount);
    }

    /**
     * 计算板块帖子点赞率
     * @param totalLikeCount 板块总帖子点赞数
     * @param totalPostCount 板块总帖数
     */
    public static Double calculateSectionPostLikeRatio(Long totalLikeCount, Long totalPostCount){
        return calculatePercentage(totalLikeCount, totalPostCount);
    }

    /**
     * 计算板块质量率
     * @param postLikeRatio 板块帖子点赞率
     * @param pinnedPostRatio 板块帖子精华率
     */
    public static Double calculateSectionQualityRatio(Double postLikeRatio, Double pinnedPostRatio){
        return addWithScale(postLikeRatio * 0.3, pinnedPostRatio * 0.7);
    }

    /**
     * 板块参与度
     * @param totalReplyCount 板块总回复数
     * @param totalLikeCount 板块总点赞数
     * @param totalFavoriteCount 板块总收藏数
     */
    public static Long calculateSectionParticipation(Long totalReplyCount, Long totalLikeCount, Long totalFavoriteCount){
        return (totalReplyCount * 2 + totalLikeCount + totalFavoriteCount * 3);
    }

    /**
     * 板块得分
     * @param sectionQualityRatio 板块质量率
     * @param sectionParticipation 板块参与度
     */
    public static Long calculateSectionScore(Double sectionQualityRatio, Long sectionParticipation){
        return toLong(addWithScale(sectionQualityRatio * 200, sectionParticipation * 0.1));
    }

    /**
     * 帖子得分
     * @param heatScore 热度分
     * @param isPinned 是否是精帖
     */
    public static Long calculatePostScore(Long heatScore, Boolean isPinned){
        return toLong(addWithScale(heatScore * 0.5, isPinned ? 200 : 0));
    }

    /**
     * 计算医生帖子平均热度
     * @param totalHeatScore 医生帖子总热度
     * @param totalPostCount 医生帖子总数
     */
    public static Long calculateAverageHeatScore(Long totalHeatScore, Long totalPostCount){
        return toLong(average(totalHeatScore, totalPostCount));
    }

    /**
     * 医生帖子点赞率
     * @param totalLikeCount 医生帖子总点赞数
     * @param totalPostCount 医生帖子总数
     */
    public static Double calculateDoctorPostLikeRatio(Long totalLikeCount, Long totalPostCount){
        return calculatePercentage(totalLikeCount, totalPostCount);
    }

    /**
     * 医生帖子精华率
     * @param pinnedPostCount 医生帖子总精华数
     * @param totalPostCount 医生帖子总数
     */
    public static Double calculateDoctorPostPinnedRatio(Long pinnedPostCount, Long totalPostCount){
        return calculatePercentage(pinnedPostCount, totalPostCount);
    }

    /**
     * 医生得分
     * @param averageHeatScore 医生帖子平均热度
     * @param doctorPostLikeRatio 医生帖子点赞率
     * @param doctorPostPinnedRatio 医生帖子精华率
     */
    public static Long calculateDoctorScore(Long averageHeatScore, Double doctorPostLikeRatio, Double doctorPostPinnedRatio){
        return toLong(addWithScale(averageHeatScore * 0.5, doctorPostLikeRatio * 150, doctorPostPinnedRatio * 200));
    }
    private static Double calculatePercentage(double numerator, double denominator) {
        if (denominator == 0) return 0.0;
        double raw = (numerator / denominator) * 100;
        return new BigDecimal(raw).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }
    /**
     * 对多个 double 值进行加法运算
     * @param values 可变参数，多个 double 值
     */
    private static double addWithScale(double... values) {
        BigDecimal sum = BigDecimal.ZERO;
        for (double val : values) {
            sum = sum.add(BigDecimal.valueOf(val));
        }
        return sum.setScale(2, RoundingMode.HALF_UP).doubleValue();
    }
    /**
     * 将 double 类型值按指定小数位数和舍入方式转换为 long 类型
     * @param value 原始 double 值
     */
    private static Long toLong(double value) {
        return new BigDecimal(value)
                .setScale(2, RoundingMode.HALF_UP)
                .longValue();
    }
    /**
     * 计算平均值，返回 double 类型
     * @param dividend 被除数（总值）
     * @param divisor 除数（数量）
     */
    private static double average(double dividend, double divisor) {
        if (divisor == 0) {
            return 0.0; // 防止除零异常
        }
        double raw = dividend / divisor;
        return new BigDecimal(raw).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }
}
